
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;


public class ComputeCash {
	final private ConcurrentHashMap<Integer, Future<Integer>> cash;
	private Compute compute;
	ComputeCash(Compute compute) {
		this.cash = new ConcurrentHashMap<Integer, Future<Integer>>();
		this.compute = compute;
	}
	synchronized Integer compute(final int arg, final int n) {
		Future<Integer> result = cash.get(arg);
		if (result == null) {
			Callable<Integer> task = new Callable<Integer>() {
				public Integer call() throws Exception{
					return compute.compute(arg, n);
				}
			};
			FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
			result =  cash.putIfAbsent(arg, futureTask);
			if (result == null) {
				futureTask.run();
				result = futureTask;
			}
			cash.put(arg, result);
		}
		else {
			result = cash.get(arg);
		}
		try {
			return result.get();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		return null;
	}
	ConcurrentHashMap<Integer, Future<Integer>> getMap() {
		return cash;
	}
}
